using System;
using System.Data.Services.Client;
using System.Linq;
using Caliburn.Micro;
using MediaOwl.Netflix.NetflixServiceReference;

namespace MediaOwl.Netflix.Data
{
    public class LoadEntityResult<T> : IResult
    {
        private DataServiceCollection<T> collection;
        private readonly IQueryable<T> qry;

        private readonly Action<T> onSuccess;
        private readonly NetflixCatalog catalog;
        private readonly Action<Exception> onFail;

        /// <summary>
        /// The constructor
        /// </summary>
        /// <param name="catalog">The Catalog</param>
        /// <param name="qry">The query</param>
        /// <param name="onSuccess">An action, that is executed on successful completion</param>
        /// <param name="onFail">An action, that is executed on failed completion</param>
        public LoadEntityResult(NetflixCatalog catalog, IQueryable<T> qry, Action<T> onSuccess = null, Action<Exception> onFail = null)
        {
            this.catalog = catalog;
            this.onFail = onFail;
            this.qry = qry;
            this.onSuccess = onSuccess;
        }

        public void Execute(ActionExecutionContext context = null)
        {
            collection = new DataServiceCollection<T>(catalog);
            collection.LoadCompleted += EntityLoaded;
            collection.LoadAsync(qry);
        }

        private void EntityLoaded(object sender, LoadCompletedEventArgs args)
        {
            if (args.Error != null || args.Cancelled)
            {
                var ex = args.Cancelled ? new Exception("LoadData was cancelled;") : args.Error;

                if (onFail != null)
                    Caliburn.Micro.Execute.OnUIThread(() => onFail(ex));

                collection.LoadCompleted -= EntityLoaded;
                Completed(this, new ResultCompletionEventArgs { Error = ex, WasCancelled = false });
                return;
            }

            if (onSuccess != null)
                Caliburn.Micro.Execute.OnUIThread(() => onSuccess(collection.FirstOrDefault()));

            collection.LoadCompleted -= EntityLoaded;         
            Completed(this, new ResultCompletionEventArgs());
            collection = null;
        }

        public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
    }
}